#coding:utf8
from copy import deepcopy
from comm import SentenceTree, get_tree_struct
import data
import comm
import json

class Rule:
    def __init__(self, rule):
        self.rule = rule
        self.rule_name = rule[0]
        self.src_tree = SentenceTree(self.to_json(rule[1]))
        self.dst_tree = SentenceTree(self.to_json(rule[2]))

    @staticmethod
    def is_match_src(to_match_src_node, actually_src_node):
        if to_match_src_node.root_token != actually_src_node.root_token:
            #print 'e1'
            return False
        to_match_children = to_match_src_node.root_children
        actually_children = actually_src_node.root_children
        if len(to_match_children) == 0:
            return True
        if len(to_match_children) != len(actually_children):
            #print 'e2', to_match_src_node.root_token, len(to_match_children), len(actually_children)
            return False
        for to_match_child, actually_child in zip(to_match_children, actually_children):
            if not Rule.is_match_src(to_match_child, actually_child):
                #print 'e3'
                return False
        return True

    def is_match(self, src_tree, dst_tree):
        if src_tree.root_token != self.src_tree.root_token:
            #print 'Token not match'
            return False
        if self.is_match_src(self.src_tree, src_tree):
            #print '%s --------match------ %s'%(src_tree, self.src_tree)
            return True
        else:
            #print '%s ---------not match-------- %s'%(src_tree, self.src_tree)
            return False

    def dst_tree_copy(self):
        return deepcopy(self.dst_tree)

    def set_tree_align(self, src_tree, template_tree = None):
        if template_tree is None:
            template_tree = self.src_tree
            if not self.is_match_src(template_tree, src_tree):
                raise ValueError('tree not match')
        if template_tree.root_align:
            #print self.rule_name, 'set align', template_tree.root_align, template_tree.root_token
            src_tree.root_align = template_tree.root_align
        for src_child, template_child in zip(src_tree.root_children, template_tree.root_children):
            self.set_tree_align(src_child, template_child)

    def __str__(self):
        return 'rule name: %s, src tree: %s, dst tree: %s' % self.rule

    def to_json(self, rule):
        if isinstance(rule, dict):
            token = rule.keys()[0].split('|')
            res = {'Token': token[0]}
            if len(token) > 1:
                res['Align'] = self.rule_name + '_' + token[1]
            child_list = []
            for child in rule.values()[0]:
                child_list.append(self.to_json(child))
            res['Child'] = child_list
            return res
        else:
            token = rule.split('|')
            if len(token) > 1:
                return {'Token': token[0], 'Align': self.rule_name + '_' + token[1]}
            else:
                return {'Token': token[0]}



class TreeTransform:
    def __init__(self):
        self.raw_rules = None

    @property
    def rules(self):
        if not self.raw_rules:
            self._load_rules()
        return self.raw_rules

    def _load_rules(self, file_name=None):
        self.raw_rules = []
        for rule in data.rules:
            self.raw_rules.append(Rule(rule))

    def transform_node(self, src_node, dst_node):
        #print 'transform_node %s ------- %s' % (src_node, dst_node)
        for rule in self.rules:
            if rule.is_match(src_node, dst_node):
                print 'Grammar rules used:', rule
                result = rule.dst_tree_copy()
                rule.set_tree_align(src_node)
                for dst_align_node in result.get_align_nodes():
                    src_align_node = src_node.get_child_by_align(dst_align_node.root_align)
                    child_result = self.transform_node(src_align_node, dst_align_node)
                    dst_align_node.update(child_result)
                return result
        else:
            result = src_node.copy_one_level()
            result.root_token = dst_node.root_token
            for src_child, dst_child in zip(src_node.root_children, result.root_children):
                child_result = self.transform_node(src_child, dst_child)
                dst_child.update(child_result)
            return result

    def transform(self, src_tree):
        #print src_tree
        old_tree = SentenceTree(src_tree)
        while True:
            dst_tree = SentenceTree();
            dst_tree.root_token = 'ROOT'
            result = self.transform_node(old_tree, dst_tree)
            if result.to_sentence() == old_tree.to_sentence():
                break
            old_tree = result
        #print 'after transform:', json.dumps(result.get_grammar(), ensure_ascii=False)
        return result


tree_transformer = TreeTransform()
del TreeTransform

if __name__ == '__main__':
    import sys
    reload(sys)
    sys.setdefaultencoding('utf8')

    from data import ch2rdb
    sentences_data = ch2rdb.get_sentence_data()
    samples = [x[0][0] for x in sentences_data]
    short_sentences = dict([x[0] for x in sentences_data])

    try:
        comm.load_cache()
#        samples = [u'有没有款式好看些的手机？']
        print comm.get_standard_sentence(samples[0])
        for sample in samples:
            print '-------------------------------------'
            result = tree_transformer.transform(get_tree_struct(sample))
            print sample
            print '  ----> '
            print comm.get_str(result.get_grammar())
            if short_sentences.get(sample, "") == result.to_sentence():
                print 'Result:  CORRECT!!'
            else:
                print 'Result:  ERROR!! Expect:  ', short_sentences.get(sample, "")
        #raw_input('PRESS ENTER TO EXIT...')
    finally:
        comm.dump_cache()
